//! 生命周期 (Lifetimes)
//!
//! 生命周期是 Rust 中的一个重要概念，它帮助编译器理解引用的有效期，
//! 确保引用在使用时始终有效，避免悬垂引用。
//!
//! ## 知识点总结
//!
//! | 知识点 | 说明 |
//! |--------|------|
//! | 生命周期注解语法 | 以撇号开头，如`'a`，用于描述引用的生命周期 |
//! | 函数中的生命周期 | 用于描述参数和返回值引用的生命周期关系 |
//! | 结构体中的生命周期 | 持有引用的结构体需要生命周期注解 |
//! | 生命周期省略规则 | 编译器在某些情况下可以自动推断生命周期 |
//! | 静态生命周期 | `'static`表示引用在整个程序运行期间都有效 |
//!
//! ## 生命周期常见场景对比
//!
//! | 场景 | 是否需要显式生命周期 | 示例 |
//! |------|-------------------|------|
//! | 函数参数都是引用，返回值也是引用 | 当有多个参数或返回值时通常需要 | `fn longest<'a>(x: &'a str, y: &'a str) -> &'a str` |
//! | 函数只有一个引用参数 | 通常不需要（生命周期省略规则1和2） | `fn first_word(s: &str) -> &str` |
//! | 方法有一个 &self 参数 | 通常不需要（生命周期省略规则3） | `fn level(&self) -> i32` |
//! | 结构体持有引用 | 总是需要 | `struct ImportantExcerpt<'a> { part: &'a str }` |
//! | 枚举持有引用 | 总是需要 | `enum Excerpt<'a> { Part(&'a str) }` |
//! | static 生命周期 | 特殊情况 | `let s: &'static str = "hello";` |

/// 1. 生命周期注解语法
/// 生命周期参数以撇号开头，通常使用小写字母命名，如 'a, 'b
pub fn lifetime_syntax() {
    println!("=== 生命周期注解语法 ===");

    // 生命周期注解并不改变任何引用的生命周期长短
    // 而是用于描述多个引用生命周期相互的关系
    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() { x } else { y }
    }

    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("较长的字符串是: {result}");
}

/// 2. 结构体中的生命周期
/// 结构体持有引用时，需要添加生命周期注解
pub fn struct_lifetimes() {
    println!("\n=== 结构体中的生命周期 ===");

    struct ImportantExcerpt<'a> {
        part: &'a str,
    }

    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("找不到 '.'");
    let i = ImportantExcerpt { part: first_sentence };

    println!("重要摘录: {}", i.part);
}

/// 3. 方法中的生命周期
/// 实现方法时，方法签名中可能也需要生命周期注解
pub fn method_lifetimes() {
    println!("\n=== 方法中的生命周期 ===");

    struct ImportantExcerpt<'a> {
        part: &'a str,
    }

    impl<'a> ImportantExcerpt<'a> {
        fn level(&self) -> i32 {
            3
        }

        fn announce_and_return_part(&self, announcement: &str) -> &str {
            println!("注意: {announcement}");
            self.part
        }
    }

    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("找不到 '.'");
    let excerpt = ImportantExcerpt { part: first_sentence };

    println!("级别: {}", excerpt.level());
    println!("返回部分: {}", excerpt.announce_and_return_part("这是重要摘录"));
}

/// 4. 静态生命周期
/// 'static 生命周期表示引用在整个程序运行期间都有效
pub fn static_lifetime() {
    println!("\n=== 静态生命周期 ===");

    let s: &'static str = "我拥有静态生命周期";
    println!("静态字符串: {s}");
}

/// 5. 生命周期省略规则
/// Rust 有三条生命周期省略规则，编译器会在特定情况下自动应用这些规则
pub fn lifetime_elision_rules() {
    println!("\n=== 生命周期省略规则 ===");

    fn first_word(s: &str) -> &str {
        s.split_whitespace().next().unwrap_or("")
    }

    let sentence = "Hello world";
    println!("第一个单词: {}", first_word(sentence));
}

/// 6. 生命周期与泛型、特性约束结合
/// 生命周期可以与泛型和特性约束一起使用
pub fn lifetime_with_generics_traits() {
    println!("\n=== 生命周期与泛型、特性约束结合 ===");

    use std::fmt::Display;

    fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
    where
        T: Display,
    {
        println!("公告: {ann}");
        if x.len() > y.len() { x } else { y }
    }

    let string1 = "abcd";
    let string2 = "xyz";

    let result = longest_with_an_announcement(string1, string2, "计算最长字符串");
    println!("结果: {result}");
}

/// 7. 生命周期与所有权、借用的关系
/// 生命周期与所有权和借用密切相关，它们共同保证了内存安全
pub fn lifetime_ownership_borrowing() {
    println!("\n=== 生命周期与所有权、借用的关系 ===");

    let x = 5;
    let y = &x;

    assert_eq!(5, *y);
    println!("x 的值: {x}");
}

/// 主演示函数
pub fn demonstrate_lifetimes() {
    lifetime_syntax();
    struct_lifetimes();
    method_lifetimes();
    static_lifetime();
    lifetime_elision_rules();
    lifetime_with_generics_traits();
    lifetime_ownership_borrowing();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_lifetime_syntax() {
        lifetime_syntax();
    }

    #[test]
    fn test_struct_lifetimes() {
        struct_lifetimes();
    }

    #[test]
    fn test_method_lifetimes() {
        method_lifetimes();
    }

    #[test]
    fn test_static_lifetime() {
        static_lifetime();
    }

    #[test]
    fn test_lifetime_elision_rules() {
        lifetime_elision_rules();
    }

    #[test]
    fn test_lifetime_with_generics_traits() {
        lifetime_with_generics_traits();
    }

    #[test]
    fn test_lifetime_ownership_borrowing() {
        lifetime_ownership_borrowing();
    }
}
